#ifndef SILL_LEARNING_DECOMPOSABLE_MOVE_HPP
#define SILL_LEARNING_DECOMPOSABLE_MOVE_HPP

#include <sill/learning/structure_old/decomposable_score.hpp>
#include <sill/model/learnt_decomposable.hpp>

#include <sill/macros_def.hpp>

namespace sill {

  /**
   * Virtual class for representing a possible move in structure search for
   * decomposable models.
   *
   * @param F         type of factor used in the decomposable model
   * @param Inserter  Inserter.push(m*, score) must insert the pointer to a
   *                  move m with score/estimate score into whatever container
   *                  collects new moves which are generated by this class.
   *
   * \author Joseph Bradley
   * \ingroup learning_structure
   */
  template <typename F, typename Inserter>
  class decomposable_move : public decomposable_change<F> {

  public:
    //! The base type
    typedef decomposable_change<F> base;

    //! The type of factor used in the decomposable model
    typedef typename base::factor_type factor_type;

    //! The type of variable associated with a factor
    typedef typename base::variable_type variable_type;

    //! The domain type of the factor
    typedef typename base::domain_type domain_type;

    //! The generic representation for clique changes
    typedef typename base::clique_change clique_change;

    //! The type of edge associated with the model
    typedef typename decomposable<F>::edge edge;

    //! The type of vertex associated with the model
    typedef typename decomposable<F>::vertex vertex;

    virtual ~decomposable_move() { }

    //! Given a model, score, and statistics class, generate all possible moves
    //! and insert pointers to them (and their scores) into the provided
    //! Inserter.
    virtual void
    generate_all_moves(const learnt_decomposable<F>& model, double cur_score,
                       const decomposable_score<F>& score, dataset_statistics<>& stats,
                       Inserter& inserter, bool use_estimates = false) const =0;

    //! Given a model, score, another decomposable_move (which has just been
    //! committed), and statistics class,
    //! generate all possible new moves of this type and insert pointers to
    //! them (and their scores) into the provided Inserter.
    virtual void
    generate_new_moves(const learnt_decomposable<F>& model, double cur_score,
                       const decomposable_score<F>& score,
                       const std::vector<clique_change>& clique_changes,
                       dataset_statistics<>& stats, Inserter& inserter,
                       bool use_estimates = false) const = 0;

  }; // class decomposable_move

} // namespace sill

#include <sill/macros_undef.hpp>

#endif // #ifndef SILL_LEARNING_DECOMPOSABLE_MOVE_HPP
